package Controlador;

import Modelo.CalculosDatos;
import Modelo.ElementoGmaps;
import Modelo.ElementoPOI;
import Modelo.GoogleMaps;
import Modelo.ListadoPOI;
import Modelo.Settings;
import Utils.Ficheros.FicheroDatos;
import Utils.GeoPoint;
import Vista.Calibracion;
import Vista.Geomantes;
import com.chaeron.GPS.event.GPSPosition;
import java.awt.Cursor;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Vector;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;

public class Controlador extends javax.swing.JFrame {

    private Geomantes geomantes; // Variable que se asigna al display para pintar todo
    private Calibracion calibracion; // Variable de la Calibración
    private Settings settings; // Variable de las opciones
    private boolean modoNavegacion; // True -> Gps
    // False -> Cursores
    private boolean modoGrabacion; //True -> Grabando ruta
    //False -> No se está guardando ruta
    private boolean mostrarRuta; //True -> Muestro la ruta
    //False -> No se muestra
    private boolean mostrarPOI; //True -> Muestro los POI
    //False -> No se muestran
    private JPanel displayMapa; // Mapa actual (Navegación o Calibración)
    private Vector vectorRuta;
    private Vector vectorRutaGeoPoint;
    //private Vector<ElementoPOI> vectorPOI;
    private ListadoPOI vectorPOI;
    private int RUTA_MAX_SIZE = 50;
    private String nombreMapa;
    private String nombreRuta;
    private int anchoPantalla;
    private int altoPantalla;
    // OPCIONES CONFIGURACION
    private boolean modoMapas;  //True -> Mapas GoogleMaps
    //False -> Mapas disco duro
    private int puertoSerie; // Puerto Serie para el Gps
    private String idioma;
    private String cuentaGoogle;
    //private ListadoPOI poi;

    // private String ruta;
    // private GeomantesDatos datos; // Variable del Gps
    // private boolean modoGoogle; // Variable indicadora del modo Google
    // private boolean modoFichero; // Variable indicadora del modo mapas de memoria
    // private boolean modoGPS; // Variable indicadora del modo gps*/
    // private boolean pintandoPOI;
    // private GPSPosition location;
    public Controlador() throws Exception {
        nombreRuta = "";
        nombreMapa = "";
        modoNavegacion = false; //Modo GPS por defecto
        modoGrabacion = false; //Por defecto no se está grabando
        mostrarRuta = true; //Por defecto se muestra la ruta
        mostrarPOI = true; //Por defecto se muestran los POI

        //Opciones iniciales
        modoMapas = true; //Modo GoogleMaps por defecto
        cuentaGoogle = "ABQIAAAAP7mVZDMT-Vpal7TCFldcLhRk-Hwz9c_--F2C22uANDjvYyeKKhRhSeYspl4gJgmqsRrqzQ-lnEgTlg";
        puertoSerie = 2;
        idioma = "es";
    }

    public Controlador getControlador() {
        return this;
    }

    public void muestraAlerta(String mensaje) {
        //Alertas.muestraProblema(mensaje, this);
    }

    //************************//
    //************************//
    //******** DISPLAY ********//
    //************************//
    //************************//
    public JPanel getDisplayMapa() {
        return displayMapa;
    }

    public void setDisplayMapa(JPanel d) {
        displayMapa = d;
    }

    public int getAnchoPantalla() {
        return anchoPantalla;
    }

    public int getAltoPantalla() {
        return altoPantalla;
    }

    public void setAnchoPantalla(int ancho) {
        anchoPantalla = ancho;
    }

    public void setAltoPantalla(int alto) {
        altoPantalla = alto;
    }

    //************************//
    //************************//
    //******** Idioma ********//
    //************************//
    //************************//
    public String getIdioma() {
        return idioma;
    }

    public void setIdioma(String i) {
        idioma = i;
    }

    //************************//
    //************************//
    //********* POIS *********//
    //************************//
    //************************//
    public void setMostrarPOI(boolean b) {
        mostrarPOI = b;
    }

    public boolean getMostrarPOI() {
        return mostrarPOI;
    }

    public void setListadoPOI(ListadoPOI p) {
        vectorPOI = p;
    }
    
    public ListadoPOI getListadoPOI() {
        return vectorPOI;
    }

    public void redibujarPOI() {
        Vector<ElementoPOI> vector = vectorPOI.getListaPOI();
        for (int i = 0; i < vector.size(); i++) {
            double latitud = vector.get(i).getLatitud();
            double longitud = vector.get(i).getLongitud();
            int[] aux = CalculosDatos.calcular(latitud,longitud);
            vector.get(i).setLatPixel(aux[2]);
            vector.get(i).setLongPixel(aux[3]);
        }
    }

    //************************//
    //************************//
    //****** GEOMANTES *******//
    //************************//
    //************************//
    public void repaintGeomantes(FicheroDatos infoLinea, int[] datosEntrada, double velocidad, double distancia) {
        geomantes.setInfoFichero(infoLinea, datosEntrada, velocidad, distancia);
        geomantes.paintBorder(null, displayMapa.getGraphics(), 0, 0, 0, 0);
    }

    public Geomantes getGeomantes() {
        return this.geomantes;
    }

    public void iniciarGeomantes() throws Exception {
        geomantes = new Geomantes();
    }

    public void reiniciarGeomantes() {
        geomantes = null;
    }

    /*
    public void resetGeomantes() {
    geomantes.reset();
    }
     */
    //************************//
    //************************//
    //******* CALIBRACION*****//
    //************************//
    //************************//
    public void calibracion(GUI.GUI_Calibracion parent) {
        calibracion = new Calibracion();
        parent.getDisplayMapa().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        calibracion.comenzar();     
        displayMapa.setBorder(calibracion);
        parent.getDisplayMapa().setCursor(Cursor.getDefaultCursor());
    }

    public Calibracion getCalibracion() {
        return this.calibracion;
    }

    //************************//
    //************************//
    //******* RUTAS **********//
    //************************//
    //************************//
    public boolean guardarRuta(Vector vectorR) {
        try {
            JFileChooser dialogGuardar = new JFileChooser();
            FileNameExtensionFilter filter = new FileNameExtensionFilter("*.rut", "rut");
            dialogGuardar.setDialogTitle("Guardar ruta");
            dialogGuardar.setFileFilter(filter);
            int seleccion = dialogGuardar.showSaveDialog(null);
            if (seleccion == dialogGuardar.APPROVE_OPTION) {
                nombreRuta = dialogGuardar.getSelectedFile().getPath();
            }
            File rutaGrabada = new File(nombreRuta + ".rut");
            rutaGrabada.createNewFile();
            FileOutputStream buffer = new FileOutputStream(rutaGrabada);

            String temp = "";
            for (int i = 0; i < vectorR.size(); i++) {
                double latitud, longitud, altitud;
                boolean continuidad;
                int continuidadInteger;
                String fecha, hora;
                latitud = ((FicheroDatos) vectorR.elementAt(i)).getLatitud();
                longitud = ((FicheroDatos) vectorR.elementAt(i)).getLongitud();
                altitud = ((FicheroDatos) vectorR.elementAt(i)).getAltitud();
                continuidad = ((FicheroDatos) vectorR.elementAt(i)).getContinuidad();
                if (continuidad) {
                    continuidadInteger = 1;
                } else {
                    continuidadInteger = 0;
                }
                fecha = ((FicheroDatos) vectorR.elementAt(i)).getFecha();
                hora = ((FicheroDatos) vectorR.elementAt(i)).getHora();

                double latitudRound = (double) (int) ((latitud + 0.0000005) * 1000000.0) / 1000000.0;
                double longitudRound = (double) (int) ((longitud + 0.0000005) * 1000000.0) / 1000000.0;
                double altitudRound = (double) (int) ((altitud + 0.05) * 10.0) / 10.0;

                temp += latitudRound + ",  " +
                        longitudRound + "," +
                        altitudRound + ", " +
                        continuidadInteger + ",, " +
                        fecha + ", " +
                        hora + "\n";
            }
            buffer.write(temp.getBytes());
            buffer.flush();
            buffer.close();
            vectorRuta = null;
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public boolean cargarRuta() throws FileNotFoundException {
        JFileChooser dialogCargar = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter("ruta.rut", "RUT");
        dialogCargar.setDialogTitle("Cargar ruta");
        dialogCargar.setFileFilter(filter);
        int seleccion = dialogCargar.showOpenDialog(null);
        if (seleccion == dialogCargar.APPROVE_OPTION) {
            nombreRuta = dialogCargar.getSelectedFile().getPath();
        }
        if (nombreRuta.compareTo("") != 0) {
            procesarRutaEnMapa();
            geomantes.paintBorder(this, displayMapa.getGraphics(), WIDTH, WIDTH, WIDTH, WIDTH);
            return true;
        }
        return false;
    }

    public void procesarRutaEnMapa() throws FileNotFoundException {
        /* Método que abre el fichero seleccionado anteriormente en "Cargar ruta"
         * y construye el vector con los puntos de la ruta.
         * Es necesario tener cargado un mapa, puesto que los puntos a dibujar
         * se calcularán según la escala de éste.*/
        FileInputStream inputStreamTxt = null;
        if (nombreRuta.compareTo("") != 0) {
            FicheroDatos infoLinea = new FicheroDatos();
            File rutaMapa = new File(nombreRuta);
            inputStreamTxt = new FileInputStream(rutaMapa);
            infoLinea.lecturaFichero(inputStreamTxt);
            vectorRuta = new Vector();
            vectorRutaGeoPoint = new Vector();
            int contadorMax = 0;
            while ((infoLinea.getLatitud() != -1) && (infoLinea.getLongitud() != -1)) {
                int[] punto = CalculosDatos.calcular(infoLinea);
                vectorRuta.addElement(punto);
                vectorRutaGeoPoint.addElement(new GeoPoint(infoLinea.getLatitud(), infoLinea.getLongitud()));
                //Vemos si el vector ha sobrepasado el tamano maximo permitido.
                //Tenemos un contador "contadorMax" que indica que parte del vector
                //ya ha sido ordenado para no volver a sustraer elementos de esa
                //parte.
                if (vectorRuta.size() > RUTA_MAX_SIZE + contadorMax) {
                    //A partir de la posicion "contadorMax" reducimos el vector a la mitad.
                    contadorMax = reduceRuta(contadorMax, 2);
                }
                infoLinea.lecturaFichero(inputStreamTxt);
            }
            //Si el vector completo supera el tamano maximo permitido, lo reducimos
            //en una pasada para que se aproxime a ese numero.
            if (vectorRuta.size() > RUTA_MAX_SIZE) {
                reduceRuta(0, vectorRuta.size() / RUTA_MAX_SIZE);
            }
            try {
                inputStreamTxt.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    private int reduceRuta(int contadorMax, int division) {
        /* Método que reduce la ruta cargada con el fin de optimizar su
         * representación en pantalla */
        int j = 0;
        for (int i = contadorMax; i < vectorRuta.size() + j; i++) {
            if (i % division != 0) {
                vectorRuta.removeElementAt(i - j);
                j++;
            }
        }
        return vectorRuta.size();
    }

    public void redibujarRuta(Vector rutaLatLong) {
        iniciaRutaMarcada();
        for (int i = 0; i < rutaLatLong.size(); i++) {
            int[] aux = CalculosDatos.calcular((FicheroDatos) rutaLatLong.elementAt(i));
            anadeVectorRuta(aux);
        }
    }

    public Vector getVectorRuta() {
        return vectorRuta;
    }

    public String getNombreRuta() {
        return nombreRuta;
    }

    public void anadeVectorRuta(int[] p) {
        if (vectorRuta == null) {
            vectorRuta = new Vector();
        }
        vectorRuta.addElement(p);
    }

    public void deshacerMarcarRuta() {
        if (vectorRuta.size() > 0) {
            vectorRuta.remove(vectorRuta.size() - 1);
        }
    }

    public void iniciaRutaMarcada() {
        vectorRuta = new Vector();
    }

    public void setModoGrabacion(boolean b) {
        modoGrabacion = b;
    }

    public boolean getModoGrabacion() {
        return modoGrabacion;
    }

    public void setMostrarRuta(boolean b) {
        mostrarRuta = b;
    }

    public boolean getMostrarRuta() {
        return mostrarRuta;
    }

    //************************//
    //************************//
    //********* GPS **********//
    //************************//
    //************************//
    public void setLocation(GPSPosition loc) {
        //location = loc;
    }

    public int getPuertoSerie() {
        return puertoSerie;
    }

    public void setPuertoSerie(int port) {
        puertoSerie = port;
    }

    public boolean getModoNavegacion() {
        return modoNavegacion;
    }

    public void setModoNavegacion(boolean b) {
        modoNavegacion = b;
    }

    //************************//
    //************************//
    //******** GOOGLE ********//
    //************************//
    //************************//
    public void guardarMapaGoogle(int n, ElementoGmaps[][] matrizGmaps, GoogleMaps googlemaps, int anchoP, int altoP) {
        googlemaps.guardar(n, matrizGmaps, anchoP, altoP);
    }

    public boolean getModoMapas() {
        return modoMapas;
    }

    public void setModoMapas(boolean b) {
        modoMapas = b;
    }

    public String getCuentaGoogle() {
        return cuentaGoogle;
    }

    public void setCuentaGoogle(String r) {
        cuentaGoogle = r;
    }

    //************************//
    //************************//
    //**** MAPAS MEMORIA *****//
    //************************//
    //************************//
    public boolean cargarMapa() throws FileNotFoundException {
        /* Método que carga un fichero .map seleccionado mediante el browser
         * y procesa la ruta cargada con respecto a este en el caso de que
         * se haya cargado alguna ruta */
        JFileChooser dialogCargar = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter(".map", "MAP");
        dialogCargar.setDialogTitle("Cargar mapa");
        dialogCargar.setFileFilter(filter);
        int seleccion = dialogCargar.showOpenDialog(null);
        if (seleccion == dialogCargar.APPROVE_OPTION) {
            nombreMapa = dialogCargar.getSelectedFile().getPath();
            CalculosDatos.setInfoFichero(nombreMapa);
            if (nombreRuta.compareTo("") != 0) {
                procesarRutaEnMapa();
                return true;
            }
            return true;
        }
        return false;
    }

    public String getNombreMapa() {
        return nombreMapa;
    }
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    //
    /*
    public String getRutaMapas() {
    return settings.getRutaMapas();
    }

    public boolean setRutaMapas(String r) {
    return settings.setRutaMapas(r);
    }
    public String getRuta() {
    return ruta;
    }
    
    public void pararGPS(boolean b) {
    getGeomantesDatos().pararGPS(b);
    }

    public boolean noGPS() {
    return getGeomantesDatos() == null;
    }

    public boolean getModoGPS() {
    return modoGPS;
    }

    public boolean getModoFichero() {
    return modoFichero;
    }

    public void setModoGPS(boolean b) {
    modoGPS = b;
    }

    public void setModoFichero(boolean b) {
    modoFichero = b;
    }
    public void guardarPOI(double latitud, double longitud) {
    //        punto = new NuevoPOI(latitud,longitud);
    }

    public void setGuardandoPOI(boolean b) {
    geomantes.setGuardandoPOI(b);
    }

    public void setPintandoPOI(boolean b) {
    pintandoPOI = b;
    }

    public boolean getPintandoPOI() {
    return pintandoPOI;
    }
    public int getAnchoPantalla() {
    return anchoPantalla;
    }

    public int getAltoPantalla() {
    return altoPantalla;
    }
    public void setAnchoPantalla(int ancho) {
    anchoPantalla = ancho;
    }

    public void setAltoPantalla(int alto) {
    altoPantalla = alto;
    }
    public void setIdioma(int index) {
    settings.setIdioma(index);
    }
    public String getIndexIdioma(int i) {
    return settings.getIndexIdioma(i);
    }

    public int getNumIdiomas() {
    return settings.getNumIdiomas();
    }

    public void setModoMapas(String mapa) {
    throw new UnsupportedOperationException("Not yet implemented");
    }

    public boolean borrarPOIpersonales() {
    return poi.borrarPOIpersonales();
    }

    public void borrarPOIpersonales(int contadorPOI) {
    poi.borrarPOIpersonales(contadorPOI);
    }

    public int getConfigPOI() {
    return settings.getConfigPOI();
    }

    public String getRutaPOI() {
    return settings.getRutaPOI();
    }

    public int getSizePOIpersonales() {
    return poi.getSizePOIpersonales();
    }

    public void guardarPOIpersonales() {
    poi.guardarPOIpersonales();
    }

    public boolean setRutaPOI(String poi) {
    return settings.setRutaPOI(poi);
    }

    public void setConfigPOI(int i) {
    settings.setConfigPOI(i);
    }

    public void setGeomantesModoGPS() {
    //geomantes.setModoGPS();
    }

    public void setGeomantesModoFichero() {
    geomantes.setModoFichero();
    }

    public void setGeomantesModoGmaps() {
    geomantes.setModoGmaps();
    }

    public Vector getPOIpersonalesEnPantalla(double lon, double lat) {
    geomantes.update(geomantes.getGraphics());
    return poi.POIpersonalesEnPantalla(lat, lon);
    }

    public void marcarPOI(double lat, double lon, String desc) {
    poi.guardarPOI(lat, lon, desc);
    }

    public int getZonaHoraria() {
    return settings.getZonaHoraria();
    }

    public boolean setZonaHoraria(int zh) {
    return settings.setZonaHoraria(zh);
    }

    public int getPrecisionLat() {
    return settings.getPrecisionLat();
    }

    public boolean setPrecisionLat(int l) {
    return settings.setPrecisionLat(l);
    }

    public int getPrecisionLong() {
    return settings.getPrecisionLong();
    }

    public boolean setPrecisionLong(int l) {
    return settings.setPrecisionLong(l);
    }

    public boolean[] getFlagsTipoGPS() {
    return settings.getFlagsTipoGPS();
    }

    public void setFlagsTipoGPS(boolean[] b) {
    settings.setFlagsTipoGPS(b);
    }

    public boolean[] getFlagsConfigGPS() {
    return settings.getFlagsConfigGPS();
    }

    public void setFlagsConfigGPS(boolean[] b) {
    settings.setFlagsConfigGPS(b);
    }

    public void reestablecerSettings() {
    settings.reestablecerSettings();
    }

    public void clearScreen() {
    geomantes.limpiaDisplay();
    }

    public void guardarSettings() {
    //settings.guardarSettings();
    }

    public boolean[] getFlagsPOI() {
    return settings.getFlagsPOI();
    }

    public void setFlagsPOI(boolean[] b) {
    settings.setFlagsPOI(b);
    }*/
}

